
#include "videoplayer.h"
#include <thread>


#define ERRMSG(errnum,func) \
    char errBuf[1024] = {}; \
    av_strerror(errnum,errBuf,sizeof (errBuf)); \
    qDebug() << #func << errBuf;


VideoPlayer::VideoPlayer(QObject *parent) : QObject(parent)
{

}

VideoPlayer::~VideoPlayer()
{

    if(_videoPath != nullptr) {

        delete [] _videoPath;
        _videoPath = nullptr;
    }

}

void VideoPlayer::setVideoPath(const char *videoPath)
{

    int len = strlen(videoPath);

    if(len > 0) {

        _videoPath = new char[len+1]{};
        memcpy((char*)_videoPath,videoPath,len);
    }


}

void VideoPlayer::play()
{

    if(_state == Playing) {

        return;
    }

    std::thread([this](){

        readVideoFile();

    }).detach();


    setState(Playing);
}

void VideoPlayer::stop()
{

    if(_state != Playing) {

        return;
    }

    setState(Stop);
}

void VideoPlayer::pause()
{

    if(_state != Playing) {

        return;
    }

    setState(Pause);
}

VideoPlayer::VideoPlayerState VideoPlayer::getState()
{

    return _state;
}

int64_t VideoPlayer::getDuration()
{

    return _fmtContext == nullptr?0:_fmtContext->duration;
}




void VideoPlayer::readVideoFile()
{

//    qDebug() <<"#### " << _videoPath;
//    return;
    int res = 0;
    res = avformat_open_input(&_fmtContext,_videoPath,nullptr,nullptr);

    if(res < 0) {

        ERRMSG(res,avformat_open_input);
        emit playError(this);
        return;
    }


    res = avformat_find_stream_info(_fmtContext,nullptr);

    if(res < 0) {

        ERRMSG(res,avformat_find_stream_info);
        emit playError(this);
        goto end;
    }

    av_dump_format(_fmtContext,0,_videoPath,0);
    fflush(stderr);

    if(initAudio()) {

        goto end;
    }

    if(initVideo()) {

        goto end;
    }

    emit initFinish(this);

end:
    avformat_free_context(_fmtContext);
    avcodec_free_context(&_audioCodecContext);
    avcodec_free_context(&_videoCodecContext);
}

int VideoPlayer::init(AVMediaType type, AVCodecContext **codecContext, AVStream **stream)
{

   int res = 0;
   res = av_find_best_stream(_fmtContext,type,-1,-1,nullptr,0);

   if(res < 0) {

       ERRMSG(res,av_find_best_stream);
       return res;
   }

   *stream = _fmtContext->streams[res];

   if(*stream == nullptr) {

       qDebug() << "not find " << type << "stream";
       return -1;
   }

   AVCodec* codec = avcodec_find_decoder((*stream)->codecpar->codec_id);

   if(codec == nullptr) {

       qDebug() << "avcodec_find_decoder" << "codec null";
       return -1;
   }

   *codecContext = avcodec_alloc_context3(codec);

   if((*codecContext) == nullptr) {

       qDebug() << "avcodec_alloc_context3" << "codec context null";
       return -1;
   }

   res = avcodec_parameters_to_context(*codecContext,(*stream)->codecpar);

   if(res < 0) {

       ERRMSG(res,avcodec_parameters_to_context);
       return -1;
   }

   res = avcodec_open2(*codecContext,codec,nullptr);

   if(res < 0) {
       ERRMSG(res,avcodec_open2);
       return -1;
   }


   return 0;
}


int VideoPlayer::initVideo()
{

    int res = init(AVMEDIA_TYPE_VIDEO,&_videoCodecContext,&_videoStream);

    if(res != 0) {

        return res;
    }

    return 0;
}

int VideoPlayer::initAudio()
{

    int res = init(AVMEDIA_TYPE_AUDIO,&_audioCodecContext,&_audioStream);

    if(res != 0) {

        return res;
    }

    return 0;
}

void VideoPlayer::setState(VideoPlayer::VideoPlayerState state)
{

    _state = state;
    emit stateChange(this);
}
